Contribuciones según apartados - Firma: Investigación previa : Manuel / Elena Redacción de las respuestas : Manuel / Elena Desarrollo código : Manuel / Elena
URL github: https://github.com/elenacanton/PRA2_R
El conjunto de datos objeto de análisis se ha obtenido a partir de este enlace en Kaggle. El dataset está formado por 12 variables (columnas) y 1599 registrs (filas).
Enlace: https://www.kaggle.com/uciml/red-wine-quality-cortez-et-al-2009?select=winequality-red.csv
Estas son las variables del conjunto de datos: 1 - fixed acidity 2 - volatile acidity 3 - citric acid 4 - residual sugar 5 - chlorides 6 - free sulfur dioxide 7 - total sulfur dioxide 8 - density 9 - pH 10 - sulphates 11 - alcohol Output variable (based on sensory data): 12 - quality (score between 0 and 10)
La principal característica de estos datos es la calidad. Con este estudio se pretende esclarecer cuáles de las características afectan a la puntuación de dicha calidad, con valores de entre 0 y 10.
Además, en la descripción del dataset publicado, ya se nos informa de que no hay valores perdidos.
# Carga de los datos
#setwd("C:/")
data <- read.csv('winequality-red.csv', sep=',', header = TRUE)
head(data)
## fixed.acidity volatile.acidity citric.acid residual.sugar chlorides
## 1 7.4 0.70 0.00 1.9 0.076
## 2 7.8 0.88 0.00 2.6 0.098
## 3 7.8 0.76 0.04 2.3 0.092
## 4 11.2 0.28 0.56 1.9 0.075
## 5 7.4 0.70 0.00 1.9 0.076
## 6 7.4 0.66 0.00 1.8 0.075
## free.sulfur.dioxide total.sulfur.dioxide density pH sulphates alcohol
## 1 11 34 0.9978 3.51 0.56 9.4
## 2 25 67 0.9968 3.20 0.68 9.8
## 3 15 54 0.9970 3.26 0.65 9.8
## 4 17 60 0.9980 3.16 0.58 9.8
## 5 11 34 0.9978 3.51 0.56 9.4
## 6 13 40 0.9978 3.51 0.56 9.4
## quality
## 1 5
## 2 5
## 3 5
## 4 6
## 5 5
## 6 5
Mostramos el resumen del conjunto de datos.
str(data)
## 'data.frame': 1599 obs. of 12 variables:
## $ fixed.acidity : num 7.4 7.8 7.8 11.2 7.4 7.4 7.9 7.3 7.8 7.5 ...
## $ volatile.acidity : num 0.7 0.88 0.76 0.28 0.7 0.66 0.6 0.65 0.58 0.5 ...
## $ citric.acid : num 0 0 0.04 0.56 0 0 0.06 0 0.02 0.36 ...
## $ residual.sugar : num 1.9 2.6 2.3 1.9 1.9 1.8 1.6 1.2 2 6.1 ...
## $ chlorides : num 0.076 0.098 0.092 0.075 0.076 0.075 0.069 0.065 0.073 0.071 ...
## $ free.sulfur.dioxide : num 11 25 15 17 11 13 15 15 9 17 ...
## $ total.sulfur.dioxide: num 34 67 54 60 34 40 59 21 18 102 ...
## $ density : num 0.998 0.997 0.997 0.998 0.998 ...
## $ pH : num 3.51 3.2 3.26 3.16 3.51 3.51 3.3 3.39 3.36 3.35 ...
## $ sulphates : num 0.56 0.68 0.65 0.58 0.56 0.56 0.46 0.47 0.57 0.8 ...
## $ alcohol : num 9.4 9.8 9.8 9.8 9.4 9.4 9.4 10 9.5 10.5 ...
## $ quality : int 5 5 5 6 5 5 5 7 7 5 ...
La variable str nos permite ver que hay 12 variables y 1599 observaciones. La variable respuesta es “quality”, la calidad del vino. El conjunto cuenta con 11 variables predictoras de clase numérica, y 1 de tipo integer, quality.
Además, vamos a realizar un análisis exploratorio de los datos. La función summary nos proporciona un resumen estadístico sobre las variables (mínimo, máximo, media, mediana, primer y tercer cuartil). Además, si hay valores faltantes también nos informará.
#Revisamos el dataset.
summary(data)
## fixed.acidity volatile.acidity citric.acid residual.sugar
## Min. : 4.60 Min. :0.1200 Min. :0.000 Min. : 0.900
## 1st Qu.: 7.10 1st Qu.:0.3900 1st Qu.:0.090 1st Qu.: 1.900
## Median : 7.90 Median :0.5200 Median :0.260 Median : 2.200
## Mean : 8.32 Mean :0.5278 Mean :0.271 Mean : 2.539
## 3rd Qu.: 9.20 3rd Qu.:0.6400 3rd Qu.:0.420 3rd Qu.: 2.600
## Max. :15.90 Max. :1.5800 Max. :1.000 Max. :15.500
## chlorides free.sulfur.dioxide total.sulfur.dioxide density
## Min. :0.01200 Min. : 1.00 Min. : 6.00 Min. :0.9901
## 1st Qu.:0.07000 1st Qu.: 7.00 1st Qu.: 22.00 1st Qu.:0.9956
## Median :0.07900 Median :14.00 Median : 38.00 Median :0.9968
## Mean :0.08747 Mean :15.87 Mean : 46.47 Mean :0.9967
## 3rd Qu.:0.09000 3rd Qu.:21.00 3rd Qu.: 62.00 3rd Qu.:0.9978
## Max. :0.61100 Max. :72.00 Max. :289.00 Max. :1.0037
## pH sulphates alcohol quality
## Min. :2.740 Min. :0.3300 Min. : 8.40 Min. :3.000
## 1st Qu.:3.210 1st Qu.:0.5500 1st Qu.: 9.50 1st Qu.:5.000
## Median :3.310 Median :0.6200 Median :10.20 Median :6.000
## Mean :3.311 Mean :0.6581 Mean :10.42 Mean :5.636
## 3rd Qu.:3.400 3rd Qu.:0.7300 3rd Qu.:11.10 3rd Qu.:6.000
## Max. :4.010 Max. :2.0000 Max. :14.90 Max. :8.000
Enumeramos el número de variables del data set.
colnames(data)
## [1] "fixed.acidity" "volatile.acidity" "citric.acid"
## [4] "residual.sugar" "chlorides" "free.sulfur.dioxide"
## [7] "total.sulfur.dioxide" "density" "pH"
## [10] "sulphates" "alcohol" "quality"
Visualizamos el tipo de datos de cada variable del conjunto de datos.
# Tipo de dato asignado a cada campo
sapply(data, function(x) class(x))
## fixed.acidity volatile.acidity citric.acid
## "numeric" "numeric" "numeric"
## residual.sugar chlorides free.sulfur.dioxide
## "numeric" "numeric" "numeric"
## total.sulfur.dioxide density pH
## "numeric" "numeric" "numeric"
## sulphates alcohol quality
## "numeric" "numeric" "integer"
Obbservamos que son todas numericas.
En el caso de los datos utilizados para esta practica solamente hay un dataset.La integración o fusión de los datos consiste en la combinación de datos procedentes de múltiples fuentes, con el fin de crear una estructura de datos coherente y única que contenga mayor cantidad de información. De lo anterior, el aparatado de integración no aplica al conjunto de datos seleccionados.
selección de variables: Ideas a valorar solo analizar las muestras cuya calidad sea superior al 7
En esta fase también es habitual realizar una exploración de los datos (screening, en inglés), con el objetivo de analizar globalmente sus características e identificar fuertes correlaciones entre atributos, de modo que se pueda prescindir de aquella información más redundante.
Idea a valorar: podríamos analizar las variables. análisis de componentes principales (ACP), apartado análisis de componentes principales (ACP),
##Análisis de componentes principales (ACP),
data.pca <- prcomp(data[,c(1:11)], center = TRUE, scale = TRUE)
summary(data.pca)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6 PC7
## Standard deviation 1.7604 1.3878 1.2452 1.1015 0.97943 0.81216 0.76406
## Proportion of Variance 0.2817 0.1751 0.1410 0.1103 0.08721 0.05996 0.05307
## Cumulative Proportion 0.2817 0.4568 0.5978 0.7081 0.79528 0.85525 0.90832
## PC8 PC9 PC10 PC11
## Standard deviation 0.65035 0.58706 0.42583 0.24405
## Proportion of Variance 0.03845 0.03133 0.01648 0.00541
## Cumulative Proportion 0.94677 0.97810 0.99459 1.00000
El resultado son 11 componentes principales (PC1-PC11), cada una de las cuales explica un porcentaje de varianza del dataset original. Así, la primera componente principal explica un poco menos de las 2/3 de la varianza total y las 5 primeras componentes describen en torno al 80 % de la varianza. Dado que las ocho primeras componentes ya explican en torno al 95 % de la varianza,
Tras aplicar la función summary, hemos podido observar que no hay ningún valor perdido en ninguna de las variables del dataset, aunque a veces los datasets, en lugar de contener NA o simplemente no tener ningún valor asignado (campo vacío), tienen 0. Sin embargo en este caso, podemos observar que solo la variable Citric acid tiene algún valor 0.
Igualmente vamos a proceder a realizar algunos test para la gestión de estos valores.
# Números de valores desconocidos por campo
sapply(data, function(x) sum(is.na(x)))
## fixed.acidity volatile.acidity citric.acid
## 0 0 0
## residual.sugar chlorides free.sulfur.dioxide
## 0 0 0
## total.sulfur.dioxide density pH
## 0 0 0
## sulphates alcohol quality
## 0 0 0
Se observa que no existen valores NA en el dataset, lo cual coincide con la descripción localizada en la url donde se aloja el conjunto de datos estudiado.
A continuación analizamos las variables con valores igual a 0 dentro del conjunto de datos.
#vemos que porcentaje por columnas tienen los valores 0
colSums(data==0)/nrow(data)*100
## fixed.acidity volatile.acidity citric.acid
## 0.000000 0.000000 8.255159
## residual.sugar chlorides free.sulfur.dioxide
## 0.000000 0.000000 0.000000
## total.sulfur.dioxide density pH
## 0.000000 0.000000 0.000000
## sulphates alcohol quality
## 0.000000 0.000000 0.000000
# Números de valores 0 por campo
colSums(data==0)
## fixed.acidity volatile.acidity citric.acid
## 0 0 132
## residual.sugar chlorides free.sulfur.dioxide
## 0 0 0
## total.sulfur.dioxide density pH
## 0 0 0
## sulphates alcohol quality
## 0 0 0
Respuesta: Se observa que existen valores 0, en la variable “citric.acid” hay 132 observaciones igual a 0.
Analizamos la posible existencia de valores no informados.
# Números de valores enpty por campo
sapply(data, function(x) sum(data==""))
## fixed.acidity volatile.acidity citric.acid
## 0 0 0
## residual.sugar chlorides free.sulfur.dioxide
## 0 0 0
## total.sulfur.dioxide density pH
## 0 0 0
## sulphates alcohol quality
## 0 0 0
Respuesta: Se observa que no existen campos no informados en el dataset.
Respuesta: A continuación vamos a explorar más detalladamente las variables para analizar la existencia de valores extremos.
Analizamos la distribución de los valores y realizamos un box-plot y un historgrama por cada una de las variables.
attach(data)
#Observamos la distribuccion de los valores de la variable :citric.acid
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(citric.acid, col=(c("#AA4371")))
boxplot(citric.acid, main="citric acid", col=(c("#0066FF")))
En la Variable “citric.acid” se entiende que las observaciones pueden ser valores reales y que estan correctamente informados. De lo anterior no aplicaremos transformaciones para estos datos.
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(fixed.acidity, col=(c("#AA4371")))
boxplot(fixed.acidity, main="fixed acidity",col=(c("#0066FF")))
En la Variable “fixed.acidity” se entiende que las observaciones pueden ser valores reales y que estan correctamente informados. De lo anterior no aplicaremos transformaciones para estos datos.
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(volatile.acidity, col=(c("#AA4371")))
boxplot(volatile.acidity, main="volatile acidity",col=(c("#0066FF")))
En la Variable “volatile.acidity” se entiende que las observaciones pueden ser valores reales y que estan correctamente informados. De lo anterior no aplicaremos transformaciones para estos datos.
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(residual.sugar, col=(c("#AA4371")))
boxplot(residual.sugar, main="residual sugar", col=(c("#0066FF")))
#existen más de 150 valores extremos en esta variable. Vamos a visualizarlos:
boxplot.stats(residual.sugar)$out
## [1] 6.10 6.10 3.80 3.90 4.40 10.70 5.50 5.90 5.90 3.80 5.10 4.65
## [13] 4.65 5.50 5.50 5.50 5.50 7.30 7.20 3.80 5.60 4.00 4.00 4.00
## [25] 4.00 7.00 4.00 4.00 6.40 5.60 5.60 11.00 11.00 4.50 4.80 5.80
## [37] 5.80 3.80 4.40 6.20 4.20 7.90 7.90 3.70 4.50 6.70 6.60 3.70
## [49] 5.20 15.50 4.10 8.30 6.55 6.55 4.60 6.10 4.30 5.80 5.15 6.30
## [61] 4.20 4.20 4.60 4.20 4.60 4.30 4.30 7.90 4.60 5.10 5.60 5.60
## [73] 6.00 8.60 7.50 4.40 4.25 6.00 3.90 4.20 4.00 4.00 4.00 6.60
## [85] 6.00 6.00 3.80 9.00 4.60 8.80 8.80 5.00 3.80 4.10 5.90 4.10
## [97] 6.20 8.90 4.00 3.90 4.00 8.10 8.10 6.40 6.40 8.30 8.30 4.70
## [109] 5.50 5.50 4.30 5.50 3.70 6.20 5.60 7.80 4.60 5.80 4.10 12.90
## [121] 4.30 13.40 4.80 6.30 4.50 4.50 4.30 4.30 3.90 3.80 5.40 3.80
## [133] 6.10 3.90 5.10 5.10 3.90 15.40 15.40 4.80 5.20 5.20 3.75 13.80
## [145] 13.80 5.70 4.30 4.10 4.10 4.40 3.70 6.70 13.90 5.10 7.80
Se decide que los valores por encima de 10 van a ser considerados outliers.
#asignamos el valor NA a los casos que van a ser considerados outliers
data$residual.sugar[data$residual.sugar>10 ] <- NA
boxplot(data$residual.sugar)
idx <- which(is.na(data$residual.sugar))
length(idx) #número de valores perdidos
## [1] 11
#Imputamos el valor de la mediana a los valores NA.
for (i in 1:length(idx)){
index <- idx[i]
data[index,]$residual.sugar <- median( data$residual.sugar, na.rm=TRUE ) #imputación
}
#mostramos los valores imputados a los NA
data$residual.sugar[idx] #mostramos el resultado
## [1] 2.2 2.2 2.2 2.2 2.2 2.2 2.2 2.2 2.2 2.2 2.2
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(data$residual.sugar, col=(c("#AA4371")))
boxplot(data$residual.sugar, main="residual sugar", col=(c("#0066FF")))
Volvemos a mostrar la distribución de los datos de la variable residual.sugar , para comprobar que no exiten valores por encima de 10.
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(chlorides, col=(c("#AA4371")))
boxplot(chlorides, main="chlorides", col=(c("#0066FF")))
#existen más de 100 valores extremos en esta variable
boxplot.stats(chlorides)$out
## [1] 0.176 0.170 0.368 0.341 0.172 0.332 0.464 0.401 0.467 0.122 0.178 0.146
## [13] 0.236 0.610 0.360 0.270 0.039 0.337 0.263 0.611 0.358 0.343 0.186 0.213
## [25] 0.214 0.121 0.122 0.122 0.128 0.120 0.159 0.124 0.122 0.122 0.174 0.121
## [37] 0.127 0.413 0.152 0.152 0.125 0.122 0.200 0.171 0.226 0.226 0.250 0.148
## [49] 0.122 0.124 0.124 0.143 0.222 0.039 0.157 0.422 0.034 0.387 0.415 0.157
## [61] 0.157 0.243 0.241 0.190 0.132 0.126 0.038 0.165 0.145 0.147 0.012 0.012
## [73] 0.039 0.194 0.132 0.161 0.120 0.120 0.123 0.123 0.414 0.216 0.171 0.178
## [85] 0.369 0.166 0.166 0.136 0.132 0.132 0.123 0.123 0.123 0.403 0.137 0.414
## [97] 0.166 0.168 0.415 0.153 0.415 0.267 0.123 0.214 0.214 0.169 0.205 0.205
## [109] 0.039 0.235 0.230 0.038
De manera análoga a la variable anterior, se decide considerar outliers a los valores superiores a 0,3. A estas observaciones se les asignará el valor de la mediana.
#asignamos el valor NA a los casos que van a ser considerados outliers
data$chlorides[data$chlorides>0.3 ] <- NA
idx <- which(is.na(data$chlorides))
length(idx) #número de valores perdidos
## [1] 22
#Imputamos el valor de la mediana a los valores NA.
for (i in 1:length(idx)){
index <- idx[i]
data[index,]$chlorides <- median( data$chlorides, na.rm=TRUE ) #imputación
}
boxplot(data$chlorides, main="chlorides", col=(c("#0066FF")))
Volvemos a mostrar la distribución de los datos de la variable chlorides , para comprobar que no exiten valores por encima de 10.
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(free.sulfur.dioxide, col=(c("#AA4371")))
boxplot(free.sulfur.dioxide, main="sulfur dioxide", col=(c("#0066FF")))
Vamos a considerar outliers los valores por encima de 60. A estas observaciones se les asignará el valor de la mediana.
#asignamos el valor NA a los casos que van a ser considerados outliers
data$free.sulfur.dioxide[data$free.sulfur.dioxide>60 ] <- NA
idx <- which(is.na(data$free.sulfur.dioxide))
length(idx) #número de valores perdidos
## [1] 4
#Imputamos el valor de la mediana a los valores NA.
for (i in 1:length(idx)){
index <- idx[i]
data[index,]$free.sulfur.dioxide <- median( data$free.sulfur.dioxide, na.rm=TRUE ) #imputación
}
boxplot(data$free.sulfur.dioxide, main="sulfur dioxide", col=(c("#0066FF")))
Revisamos que ya no exsistan valores por encima de 60 en esta variable.
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(total.sulfur.dioxide, col=(c("#AA4371")))
boxplot(total.sulfur.dioxide, main="total sulfur dioxide", col=(c("#0066FF")))
Vamos a considerar outliers los valores por encima de 170. A estas observaciones se les asignará el valor de la mediana.
#asignamos el valor NA a los casos que van a ser considerados outliers
data$total.sulfur.dioxide[data$total.sulfur.dioxide>170 ] <- NA
idx <- which(is.na(data$total.sulfur.dioxide))
length(idx) #número de valores perdidos
## [1] 2
#Imputamos el valor de la mediana a los valores NA.
for (i in 1:length(idx)){
index <- idx[i]
data[index,]$total.sulfur.dioxide <- median( data$total.sulfur.dioxide, na.rm=TRUE ) #imputación
}
boxplot(data$total.sulfur.dioxide, main="total sulfur dioxide", col=(c("#0066FF")))
Comprobamos que ya no exiten valores por encima de 170.
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(density, col=(c("#AA4371")))
boxplot(density, main="density", col=(c("#0066FF")))
En la Variable “density” se entiende que las observaciones pueden ser valores reales y que estan correctamente informadas. De lo anterior no aplicaremos transformaciones para estos datos.
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(pH, col=(c("#AA4371")))
boxplot(pH, main="pH", col=(c("#0066FF")))
En la Variable “ph” se entiende que las observaciones pueden ser valores reales y que están correctamente informados. De lo anterior no aplicaremos transformaciones para estos datos.
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(sulphates, col=(c("#AA4371")))
boxplot(sulphates, main="sulphates", col=(c("#0066FF")))
Vamos a considerar outliers los valores por encima de 1,5. A estas observaciones se les asignará el valor de la mediana.
#asignamos el valor NA a los casos que van a ser considerados outliers
data$sulphates[data$sulphates>1.5 ] <- NA
idx <- which(is.na(data$sulphates))
length(idx) #número de valores perdidos
## [1] 8
#Imputamos el valor de la mediana a los valores NA.
for (i in 1:length(idx)){
index <- idx[i]
data[index,]$sulphates <- median( data$sulphates, na.rm=TRUE ) #imputación
}
boxplot(data$sulphates, main="sulphates", col=(c("#0066FF")))
Comprobamos que ya no exisnte valores por encima de 1,5
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(alcohol, col=(c("#AA4371")))
boxplot(alcohol, main="alcohol", col=(c("#0066FF")))
En la Variable “alcohol” se entiende que las observaciones pueden ser valores reales y que están correctamente informadas. De lo anterior no aplicaremos transformaciones para estos datos.
par(mfrow=c(1,2)) # set the plotting area into a 1*2 array
hist(quality, col=(c("#AA4371")))
boxplot(quality, main="quality", col=(c("#0066FF")))
###podemos considerarla categoricas
residual.sugar: se decide que los valores por encima de 10 van a ser considerados outliers. chlorides: se decide considerar outliers a los valores superiores a 0,3 free.sulfur.dioxide: se decide considerar outliers los valores por encima de 60. total.sulfur.dioxide: se considerar outliers los valores por encima de 170. sulphates: se decide considerar outliers los valores por encima de 1,5.
A todos esos casos se ha decidido imputar el valor de la mediana, exluidos los casos considerados outliers.
En el resto de variables. no se han realizado modificaciones de los datos.
Análisis de los casos según el nivel de alcohol.
vinos.calidadAlta <- data[data$quality >= 7,]
#Se obtienen 217 observaciones
NROW(vinos.calidadAlta)
## [1] 217
#En términos porcentuales supone un 13,57%
NROW(vinos.calidadAlta)/NROW(data)
## [1] 0.1357098
Existen 217 muestras cuyos valores de la variable quality es igual o superior a 7, lo que supone un 13,57% sobre el total del dataset.
Indicar que por el teorema del límite central, podemos asumir normalidad, puesto que tenemos una muestra de tamaño grande n=1600 observaciones y se desea realizar un test sobre la media.
Analizamos la normalidad la variables con el ad.test de la libreria nortest.
#install.packages("nortest")
library(nortest)
alpha = 0.05
col.names = colnames(data)
for (i in 1:ncol(data)) {
if (i == 1) cat("Variables que no siguen una distribución normal:\n")
if (is.integer(data[,i]) | is.numeric(data[,i])) {
p_val = ad.test(data[,i])$p.value
if (p_val < alpha) {
cat(col.names[i])
# Format output
if (i < ncol(data) - 1) cat("\n")
if (i %% 3 == 0) cat("")
}
}
}
## Variables que no siguen una distribución normal:
## fixed.acidity
## volatile.acidity
## citric.acid
## residual.sugar
## chlorides
## free.sulfur.dioxide
## total.sulfur.dioxide
## density
## pH
## sulphates
## alcoholquality
Analizamos la normalidad con el ‘density plot’ y el ‘qqplot’
par(mfrow=c(1,2))
plot(density(fixed.acidity),main="Density")
qqnorm(fixed.acidity)
fixed.acidity: parece seguir una distribución normal observando el grafico : q-q
par(mfrow=c(1,2))
plot(density(volatile.acidity),main="Density")
qqnorm(volatile.acidity)
volatile.acidity: parece seguir una distribución normal observando el grafico : q-q
par(mfrow=c(1,2))
plot(density(citric.acid),main="Density")
qqnorm(citric.acid)
citric.acid: su extremo izquierdo se desvía de la normal observando el grafico : q-q
par(mfrow=c(1,2))
plot(density(residual.sugar),main="Density")
qqnorm(residual.sugar)
residual.sugar: los valores centrales se desvían de la normal observando el grafico : q-q
par(mfrow=c(1,2))
plot(density(chlorides),main="Density")
qqnorm(chlorides)
chlorides: los valores centrales se desvían de la normal observando el grafico : q-q
par(mfrow=c(1,2))
plot(density(free.sulfur.dioxide),main="Density")
qqnorm(free.sulfur.dioxide)
free.sulfur.dioxide: parece seguir una distribución normal observando el grafico : q-q
par(mfrow=c(1,2))
plot(density(total.sulfur.dioxide),main="Density")
qqnorm(total.sulfur.dioxide)
total.sulfur.dioxide: parece seguir una distribución normal observando el grafico : q-q
par(mfrow=c(1,2))
plot(density(density),main="Density")
qqnorm(density)
density(density , parece seguir una distribución normal observando el grafico : q-q
par(mfrow=c(1,2))
plot(density(pH),main="Density")
qqnorm(pH)
density(pH): parece seguir una distribución normal observando el grafico : q-q
par(mfrow=c(1,2))
plot(density(sulphates),main="Density")
qqnorm(sulphates)
sulphates: parece seguir una distribución normal observando el grafico : q-q
par(mfrow=c(1,2))
plot(density(alcohol),main="Density")
qqnorm(alcohol)
Seguidamente, pasamos a estudiar la homogeneidad de varianzas mediante la aplicación de un test de Fligner-Killeen. En este caso, estudiaremos esta homogeneidad. En el siguiente test, la hipótesis nula consiste en que ambas varianzas son iguales.
fligner.test(quality ~ residual.sugar, data = data)
##
## Fligner-Killeen test of homogeneity of variances
##
## data: quality by residual.sugar
## Fligner-Killeen:med chi-squared = 75.977, df = 82, p-value = 0.6664
Puesto que obtenemos un p-valor superior a 0,05, aceptamos la hipótesis de que las varianzas de ambas muestras son homogéneas.
summary(alcohol)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.40 9.50 10.20 10.42 11.10 14.90
Contraste de hipótesis:
Se aplica la prueba estadistica de contraste de hipótesis sobre dos muestras para determinar si el nivel de calidad el vino es diferente dependiendo de la categoría calculada en función del alcohol. Se considera nivel bajo de alcohol las muestras con un valor por debajo de la media (10.42) y nivel alto cuando la muestra tiene un valor superior o igual a 10.42.
Para ello, tendremos dos categorias: - Vinos con nivel bajo de alcohol - Vinos con nivel alto de alcohol
data_AlcoholBajo <- data[data$alcohol < 10.42,]$quality
data_AlcoholAlto <- data[data$alcohol >= 10.42,]$quality
Nos preguntamos si la calidad del los vinos puede ser diferente en función de la categoría creada en función del grado de alcohol de la muestras. (anteriormente descrita)
En este escenario la hipótesis nula y la alternativa.
H0 : μAlcBajo = μAlcAlto
H1 : μAlcBajo =! μAlcAlto
Es un test de dos muestras sobre la media con varianzas desconocidas. Por el teorema del límite central, podemos asumir normalidad. Comprobamos igualdad de varianzas:
var.test( data_AlcoholBajo, data_AlcoholAlto )
##
## F test to compare two variances
##
## data: data_AlcoholBajo and data_AlcoholAlto
## F = 0.59219, num df = 915, denom df = 682, p-value = 1.624e-13
## alternative hypothesis: true ratio of variances is not equal to 1
## 95 percent confidence interval:
## 0.5142841 0.6809068
## sample estimates:
## ratio of variances
## 0.5921906
El resultado del test es un valor p<0.05. Por tanto, asumimos diferencias de varianzas. En consecuencia, el test se corresponde con un test de dos muestras independientes sobre la media con varianzas desconocidas diferentes. El test es bilateral.
t.test( data_AlcoholBajo, data_AlcoholAlto,
var.equal=FALSE, alternative="two.sided")
##
## Welch Two Sample t-test
##
## data: data_AlcoholBajo and data_AlcoholAlto
## t = -17.688, df = 1237.4, p-value < 2.2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -0.7569536 -0.6057987
## sample estimates:
## mean of x mean of y
## 5.344978 6.026354
Conclusión: Nos encontramos con un p-value por debajo de 0.05 por lo que podemos indicar que podemos aceptar la hipótesis alternativa. Podemos indicar que la calidad de los vinos es diferente entre los considerados como nivel bajo de alcohol y los vinos con un nivel alto de alcohol con un nivel de confianza del 95%.
#install.packages("ggplot2")
library("ggplot2")
data$AlcoholCat <- ifelse(data$alcohol < 10.42 , "Bajo", "Alto")
#diagramas de caja: distribución de la variable ‘Weight‘ según la variable ‘portero‘
ggplot(data =data, aes(x=AlcoholCat,y=quality)) + geom_boxplot()
Representación gráfica del nivel de calidad frente a la categorías realizadas en función de las variables de alcohol consideradas.
Análisis de la correlación.
corr_matrix <- matrix(nc = 2, nr = 0)
colnames(corr_matrix) <- c("estimate", "p-value")
# Calcular el coeficiente de correlación para cada variable cuantitativa
# con respecto al campo "quality"
for (i in 1:(ncol(data) - 1)) {
if (is.integer(data[,i]) | is.numeric(data[,i])) {
spearman_test = cor.test(data[,i],data$quality,method = "spearman")
corr_coef = spearman_test$estimate
p_val = spearman_test$p.value
# Add row to matrix
pair = matrix(ncol = 2, nrow = 1)
pair[1][1] = corr_coef
pair[2][1] = p_val
corr_matrix <- rbind(corr_matrix, pair)
rownames(corr_matrix)[nrow(corr_matrix)] <- colnames(data)[i]
}
}
## Warning in cor.test.default(data[, i], data$quality, method = "spearman"):
## Cannot compute exact p-value with ties
## Warning in cor.test.default(data[, i], data$quality, method = "spearman"):
## Cannot compute exact p-value with ties
## Warning in cor.test.default(data[, i], data$quality, method = "spearman"):
## Cannot compute exact p-value with ties
## Warning in cor.test.default(data[, i], data$quality, method = "spearman"):
## Cannot compute exact p-value with ties
## Warning in cor.test.default(data[, i], data$quality, method = "spearman"):
## Cannot compute exact p-value with ties
## Warning in cor.test.default(data[, i], data$quality, method = "spearman"):
## Cannot compute exact p-value with ties
## Warning in cor.test.default(data[, i], data$quality, method = "spearman"):
## Cannot compute exact p-value with ties
## Warning in cor.test.default(data[, i], data$quality, method = "spearman"):
## Cannot compute exact p-value with ties
## Warning in cor.test.default(data[, i], data$quality, method = "spearman"):
## Cannot compute exact p-value with ties
## Warning in cor.test.default(data[, i], data$quality, method = "spearman"):
## Cannot compute exact p-value with ties
## Warning in cor.test.default(data[, i], data$quality, method = "spearman"):
## Cannot compute exact p-value with ties
## Warning in cor.test.default(data[, i], data$quality, method = "spearman"):
## Cannot compute exact p-value with ties
corr_matrix
## estimate p-value
## fixed.acidity 0.11408367 4.801220e-06
## volatile.acidity -0.38064651 2.734944e-56
## citric.acid 0.21348091 6.158952e-18
## residual.sugar 0.03270283 1.912021e-01
## chlorides -0.18332346 1.494955e-13
## free.sulfur.dioxide -0.05485346 2.827937e-02
## total.sulfur.dioxide -0.20048430 5.826244e-16
## density -0.17707407 9.918139e-13
## pH -0.04367193 8.084594e-02
## sulphates 0.38395957 2.537306e-57
## alcohol 0.47853169 2.726838e-92
## quality 1.00000000 0.000000e+00
Así, identificamos cuáles son las variables más correlacionadas con la calidad del vino en función de su proximidad con los valores -1 y +1. Teniendo esto en cuenta, queda patente cómo la variable más relevante en la calidad del vino es el alcohol . Nota. Para cada coeficiente de correlación se muestra también su p-valor asociado, puesto que éste puede dar información acerca del peso estadístico de la correlación obtenida.
Correlacion con la variable Quality:
corr.res<-cor(data[,-13], method="spearman")
corr.res
## fixed.acidity volatile.acidity citric.acid residual.sugar
## fixed.acidity 1.00000000 -0.27828222 0.661708417 0.22061984
## volatile.acidity -0.27828222 1.00000000 -0.610259467 0.03838806
## citric.acid 0.66170842 -0.61025947 1.000000000 0.17281554
## residual.sugar 0.22061984 0.03838806 0.172815538 1.00000000
## chlorides 0.24948756 0.16292441 0.085052679 0.23681569
## free.sulfur.dioxide -0.17026090 0.01908994 -0.074407514 0.06093500
## total.sulfur.dioxide -0.08851961 0.09732612 0.005880251 0.13128825
## density 0.62307076 0.02501412 0.352285261 0.41263833
## pH -0.70667359 0.23357152 -0.548026276 -0.08406679
## sulphates 0.21263218 -0.32845414 0.329490517 0.04180563
## alcohol -0.06657566 -0.22493168 0.096455544 0.12950596
## quality 0.11408367 -0.38064651 0.213480914 0.03270283
## chlorides free.sulfur.dioxide total.sulfur.dioxide
## fixed.acidity 0.249487559 -0.170260896 -0.088519608
## volatile.acidity 0.162924412 0.019089943 0.097326120
## citric.acid 0.085052679 -0.074407514 0.005880251
## residual.sugar 0.236815693 0.060935002 0.131288245
## chlorides 1.000000000 -0.005331721 0.128941252
## free.sulfur.dioxide -0.005331721 1.000000000 0.783791037
## total.sulfur.dioxide 0.128941252 0.783791037 1.000000000
## density 0.414069187 -0.045902592 0.133054752
## pH -0.204374649 0.114175693 -0.006302514
## sulphates -0.022873613 0.044009451 -0.008090304
## alcohol -0.261929083 -0.080067784 -0.261431180
## quality -0.183323461 -0.054853464 -0.200484301
## density pH sulphates alcohol
## fixed.acidity 0.62307076 -0.706673595 0.212632177 -0.06657566
## volatile.acidity 0.02501412 0.233571519 -0.328454141 -0.22493168
## citric.acid 0.35228526 -0.548026276 0.329490517 0.09645554
## residual.sugar 0.41263833 -0.084066795 0.041805632 0.12950596
## chlorides 0.41406919 -0.204374649 -0.022873613 -0.26192908
## free.sulfur.dioxide -0.04590259 0.114175693 0.044009451 -0.08006778
## total.sulfur.dioxide 0.13305475 -0.006302514 -0.008090304 -0.26143118
## density 1.00000000 -0.312055078 0.159942063 -0.46244458
## pH -0.31205508 1.000000000 -0.067479602 0.17993243
## sulphates 0.15994206 -0.067479602 1.000000000 0.21641153
## alcohol -0.46244458 0.179932427 0.216411535 1.00000000
## quality -0.17707407 -0.043671935 0.383959571 0.47853169
## quality
## fixed.acidity 0.11408367
## volatile.acidity -0.38064651
## citric.acid 0.21348091
## residual.sugar 0.03270283
## chlorides -0.18332346
## free.sulfur.dioxide -0.05485346
## total.sulfur.dioxide -0.20048430
## density -0.17707407
## pH -0.04367193
## sulphates 0.38395957
## alcohol 0.47853169
## quality 1.00000000
#install.packages("corrplot")
#library(corrplot)
corrplot::corrplot.mixed(corr.res, upper="ellipse",number.cex=.6,tl.cex=.6)
Se analiza adicionalmente la correlación de forma gráfica.
library(corrplot)
## corrplot 0.88 loaded
par(mfrow = c(1,1))
cor.data <- cor(data[,-13])
corrplot(cor.data, method = 'number')
Se pueden apreciar relaciones débiles entre residual sugar, free sulfur dioxide, ph, fixed acidity y density con respecto a la variable que tratamos de explicar, quality.
Modelo de regresión lineal:
Incialmente realizamos un modelo lineal con las 4 variables más correlacionadas con la variable “quality”
modelo1 <- lm(quality ~ alcohol +volatile.acidity + sulphates + citric.acid )
summary(modelo1)
##
## Call:
## lm(formula = quality ~ alcohol + volatile.acidity + sulphates +
## citric.acid)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.71408 -0.38590 -0.06402 0.46657 2.20393
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.64592 0.20106 13.160 < 2e-16 ***
## alcohol 0.30908 0.01581 19.553 < 2e-16 ***
## volatile.acidity -1.26506 0.11266 -11.229 < 2e-16 ***
## sulphates 0.69552 0.10311 6.746 2.12e-11 ***
## citric.acid -0.07913 0.10381 -0.762 0.446
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.6588 on 1594 degrees of freedom
## Multiple R-squared: 0.3361, Adjusted R-squared: 0.3345
## F-statistic: 201.8 on 4 and 1594 DF, p-value: < 2.2e-16
# Intervalos de confianza
confint(modelo1)
## 2.5 % 97.5 %
## (Intercept) 2.2515575 3.0402782
## alcohol 0.2780728 0.3400835
## volatile.acidity -1.4860436 -1.0440733
## sulphates 0.4932780 0.8977542
## citric.acid -0.2827462 0.1244961
# En caso de querer los intervalos basados en el error estándar.
confint.default(modelo1)
## 2.5 % 97.5 %
## (Intercept) 2.2518569 3.0399788
## alcohol 0.2780963 0.3400600
## volatile.acidity -1.4858758 -1.0442411
## sulphates 0.4934316 0.8976006
## citric.acid -0.2825916 0.1243415
Posteriormente realizamos un modelo lineal con las 5 variables más correlacionadas con la variable “quality” (simplemente añadimos total sulfur dioxide al modelo anterior)
modelo2 <- lm(quality ~ alcohol +volatile.acidity + sulphates + citric.acid + total.sulfur.dioxide)
summary(modelo2)
##
## Call:
## lm(formula = quality ~ alcohol + volatile.acidity + sulphates +
## citric.acid + total.sulfur.dioxide)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.72463 -0.38380 -0.06689 0.44606 2.14550
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.8431068 0.2050732 13.864 < 2e-16 ***
## alcohol 0.2953419 0.0160375 18.416 < 2e-16 ***
## volatile.acidity -1.2223102 0.1124774 -10.867 < 2e-16 ***
## sulphates 0.7207881 0.1027039 7.018 3.32e-12 ***
## citric.acid -0.0427246 0.1035810 -0.412 0.68
## total.sulfur.dioxide -0.0022182 0.0005126 -4.327 1.60e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.6552 on 1593 degrees of freedom
## Multiple R-squared: 0.3439, Adjusted R-squared: 0.3418
## F-statistic: 167 on 5 and 1593 DF, p-value: < 2.2e-16
# Intervalos de confianza
confint(modelo2)
## 2.5 % 97.5 %
## (Intercept) 2.440865047 3.245348455
## alcohol 0.263885167 0.326798655
## volatile.acidity -1.442929393 -1.001690996
## sulphates 0.519339183 0.922237030
## citric.acid -0.245894093 0.160444848
## total.sulfur.dioxide -0.003223673 -0.001212781
# En caso de querer los intervalos basados en el error estándar.
confint.default(modelo2)
## 2.5 % 97.5 %
## (Intercept) 2.441170667 3.245042835
## alcohol 0.263909067 0.326774754
## volatile.acidity -1.442761768 -1.001858621
## sulphates 0.519492243 0.922083970
## citric.acid -0.245739727 0.160290481
## total.sulfur.dioxide -0.003222909 -0.001213545
Finalmente realizamos un modelo lineal con las 7 variables más correlacionadas con la variable “quality” (simplemente añadimos total density al modelo anterior)
modelo3 <- lm(quality ~ alcohol +volatile.acidity + sulphates + citric.acid + chlorides +total.sulfur.dioxide +density)
summary(modelo3)
##
## Call:
## lm(formula = quality ~ alcohol + volatile.acidity + sulphates +
## citric.acid + chlorides + total.sulfur.dioxide + density)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.67819 -0.38067 -0.06311 0.44428 2.05461
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.9529094 11.9896065 -0.079 0.937
## alcohol 0.2802878 0.0202744 13.825 < 2e-16 ***
## volatile.acidity -1.1144889 0.1197464 -9.307 < 2e-16 ***
## sulphates 0.9025477 0.1122700 8.039 1.75e-15 ***
## citric.acid 0.0444070 0.1236454 0.359 0.720
## chlorides -1.7474785 0.4056573 -4.308 1.75e-05 ***
## total.sulfur.dioxide -0.0023195 0.0005138 -4.514 6.82e-06 ***
## density 3.9230934 11.9441494 0.328 0.743
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.6517 on 1591 degrees of freedom
## Multiple R-squared: 0.3517, Adjusted R-squared: 0.3488
## F-statistic: 123.3 on 7 and 1591 DF, p-value: < 2.2e-16
Al revisar R-squared, se observa cómo al ir incluyendo más variables se mejora, aunque no mucho, la precisión del modelo.
# Intervalos de confianza
confint(modelo3)
## 2.5 % 97.5 %
## (Intercept) -24.469996853 22.564178123
## alcohol 0.240520525 0.320055120
## volatile.acidity -1.349366182 -0.879611611
## sulphates 0.682334966 1.122760383
## citric.acid -0.198118011 0.286932040
## chlorides -2.543157645 -0.951799434
## total.sulfur.dioxide -0.003327297 -0.001311684
## density -19.504831974 27.351018799
# En caso de querer los intervalos basados en el error estándar.
confint.default(modelo3)
## 2.5 % 97.5 %
## (Intercept) -24.452106293 22.546287563
## alcohol 0.240550778 0.320024867
## volatile.acidity -1.349187499 -0.879790293
## sulphates 0.682502492 1.122592856
## citric.acid -0.197933511 0.286747540
## chlorides -2.542552334 -0.952404745
## total.sulfur.dioxide -0.003326531 -0.001312451
## density -19.487009244 27.333196069
Regresion logistica:
Creamos una variable dicotómica para aplicar la regresión logistica. CalidadAlta será igual a 1 cuando los valores de la variable quality sean superiores o iguales a 6
data$CalidadAlta <- ifelse( data$quality >=6 , 1, 0)
#revisamos los valores
table(data$quality, data$CalidadAlta)
##
## 0 1
## 3 10 0
## 4 53 0
## 5 681 0
## 6 0 638
## 7 0 199
## 8 0 18
Revisamos los valores introducidos en la nueva variable y su relación con el contenido en la variable “quality”
model.logist1=glm(formula=CalidadAlta ~ alcohol +volatile.acidity +sulphates+citric.acid +chlorides+total.sulfur.dioxide, data = data,family=binomial(link=logit))
summary(model.logist1)
##
## Call:
## glm(formula = CalidadAlta ~ alcohol + volatile.acidity + sulphates +
## citric.acid + chlorides + total.sulfur.dioxide, family = binomial(link = logit),
## data = data)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -3.0992 -0.8477 0.3166 0.8562 2.3680
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -8.48525 0.86548 -9.804 < 2e-16 ***
## alcohol 0.90564 0.07112 12.734 < 2e-16 ***
## volatile.acidity -3.50967 0.45134 -7.776 7.48e-15 ***
## sulphates 2.91628 0.44170 6.602 4.05e-11 ***
## citric.acid -0.89010 0.39249 -2.268 0.0233 *
## chlorides 0.50032 2.45127 0.204 0.8383
## total.sulfur.dioxide -0.01226 0.00205 -5.979 2.25e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 2209.0 on 1598 degrees of freedom
## Residual deviance: 1668.9 on 1592 degrees of freedom
## AIC: 1682.9
##
## Number of Fisher Scoring iterations: 4
Relativo al contraste de hipotesis, podemos observar:
library("ggplot2")
data$AlcoholCat <- ifelse(data$alcohol < 10.42 , "Bajo", "Alto")
ggplot(data =data, aes(x=AlcoholCat,y=quality, color = AlcoholCat )) + geom_boxplot() +
geom_jitter(width = 0.1)
En esta representación de la calidad relacionada con el alcohol de las muestras. Podemos observar que para las muestras consideradas nivel de alcohol Alto, se obtiene un valor de quality superior a la quality de las muestras consideras nivel bajo de alcohol.
A continuación vamos a Visualizar los datos asociados a cada modelo, en especial el grafico Normal Q-Q y el gráfico de residuos frente valores ajustados,
layout(matrix(c(1,2,3,4),2,2))
plot(modelo1)
layout(matrix(c(1,2,3,4),2,2))
plot(modelo2)
layout(matrix(c(1,2,3,4),2,2))
plot(modelo3)
# Con las siguientes representaciones, nos hacemos una idea de cómo se comportan las variables alcohol,volatile.acidity, sulphates, citric.acid, total.sulfur.dioxide y density, en relación con la calidad del vino
scatter.smooth(data$quality, data$alcohol)
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
scatter.smooth(data$quality, data$volatile.acidity)
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
scatter.smooth(data$quality, data$sulq)
scatter.smooth(data$quality, data$citric.acid)
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
scatter.smooth(data$quality, data$total.sulfur.dioxide)
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
scatter.smooth(data$quality, data$density)
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## pseudoinverse used at 5
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## neighborhood radius 1
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## reciprocal condition number 0
## Warning in simpleLoess(y, x, w, span, degree = degree, parametric = FALSE, :
## There are other near singularities as well. 1
Realizamos una tabla de comparación entre los modelos lineales implementados.
# Tabla con los coeficientes de determinación de cada modelo
tabla.coeficientes <- matrix(c(
1, summary(modelo1)$r.squared,
2, summary(modelo2)$r.squared,
3, summary(modelo3)$r.squared), ncol = 2, byrow = TRUE)
colnames(tabla.coeficientes) <- c("Modelo", "R^2")
tabla.coeficientes
## Modelo R^2
## [1,] 1 0.3361393
## [2,] 2 0.3438525
## [3,] 3 0.3516932
Se observa que el modelo lineal 3 es ligeramente mejor que sus predecesores.
Respecto al modelo logistico podemos realizar la visualización de los odds ratio de las variables regresoras mediante un intervalo de confianza del 95% e interpreta los intervalos obtenidos. ¿Qué regresor tiene más impacto en la probabilidad de calidad alta del vino?
exp(cbind(coef(model.logist1),confint(model.logist1)))
## Waiting for profiling to be done...
## 2.5 % 97.5 %
## (Intercept) 2.064915e-04 3.704236e-05 1.103863e-03
## alcohol 2.473523e+00 2.157031e+00 2.851013e+00
## volatile.acidity 2.990667e-02 1.217130e-02 7.148419e-02
## sulphates 1.847251e+01 7.840845e+00 4.438928e+01
## citric.acid 4.106158e-01 1.894415e-01 8.832982e-01
## chlorides 1.649255e+00 1.269212e-02 1.944006e+02
## total.sulfur.dioxide 9.878187e-01 9.838110e-01 9.917551e-01
Podemos indicar que el mayor impacto en incrementar la calidad del vino es alcohol.
#install.packages("caret")
#install.packages("e1071")
#Import required library
library(caret)
## Loading required package: lattice
Estimación de la precisión del modelo logistico Vamos a proporcionar la tabla de confusión correspondiente al modelo.
Se adopta como criterio que las predicciones obtenidas con el modelo logístico por encima de 0,5 pertenecerían al grupo de calidad alta. Anteriormente hemos definido: CalidadAlta será igual a 1 cuando los valores de la variable quality sean superiores o iguales a 6
confusionMatrix(table(predict(model.logist1, type="response") >= 0.5,data$CalidadAlta == "1"))
## Confusion Matrix and Statistics
##
##
## FALSE TRUE
## FALSE 539 213
## TRUE 205 642
##
## Accuracy : 0.7386
## 95% CI : (0.7163, 0.76)
## No Information Rate : 0.5347
## P-Value [Acc > NIR] : <2e-16
##
## Kappa : 0.475
##
## Mcnemar's Test P-Value : 0.7321
##
## Sensitivity : 0.7245
## Specificity : 0.7509
## Pos Pred Value : 0.7168
## Neg Pred Value : 0.7580
## Prevalence : 0.4653
## Detection Rate : 0.3371
## Detection Prevalence : 0.4703
## Balanced Accuracy : 0.7377
##
## 'Positive' Class : FALSE
##
Se obteniene de esta manera que el modelo logístico tiene una precisión superior al 70%.
En el preprocesamiento de los datos valores extremos (outliers), se han utilizado los siguientes criterios adoptados según las variables del conjunto de datos: -residual.sugar: Se decide que los valores por encima de 10 van a ser considerados outliers. -chlorides: se decide considerar outliers a los valores superiores a 0,3 -free.sulfur.dioxide: se decide considerar outliers los valores por encima de 60. -total.sulfur.dioxide: se considerar outliers los valores por encima de 170. -sulphates: se decide considerar outliers los valores por encima de 1,5.
A todos esos casos se ha decidido imputar el valor de la mediana, exluidos los casos considerados outliers.
En el resto de variables. no se han realizado modificaciones de los datos.
De análisis de los datos, podemos indicar que:
Del contraste de hipotesis realizado, la calidad de los vinos es diferente entre los considerados como nivel bajo de alcohol y nivel alto, con un nivel de confianza del 95%. Por lo observado, parece que el nivel de calidad puede ser superior para los vinos con un nivel alto de alcohol.
Del análisis de la correlaciones podemos indicar que las variables alcohol, volatile.acidity, sulphates, citric.acid y chlorides son las más correlacionadas con el nivel de calidad de los vinos del dataset. Esto significa que son las variables del dataset que ejercen una mayor influencia sobre el la calidad del vino.
Adicionalmente hemos realizados diferentes modelos de regresión, lineales y logística, que serían útiles para realizar predicciones sobre la calidad dadas unas características concretas, de las otras variables.
De lo anterior podemos indicar que del análisis de los datos podemos aclarar cómo algunas de las variables del conjunto de datos están relacionadas con el problema planteado, conocer la calidad del vino.
#exportacion de datos tras el tratamiento:
# write.csv(data,"C:\\Users\\Usuario\\winquality_modificado.csv", row.names = FALSE) # Para especificar un directorio distinto al actual
# Con la siguiente función se exportan los datos a un fichero csv llamado winequality_modificado en el working directory en el que estemos trabajando.
write.csv(data,'winequality_modificado.csv', row.names = FALSE)